package cn.com.org.controller.wsocket;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import cn.com.org.base.WsocketConfigurator;



@ServerEndpoint(value = "/chat/{uuuu}/{aaaa}", configurator = WsocketConfigurator.class)
public class WebsocketChat {
	private static final String GUEST_PREFIX = "visitor";
	private static final AtomicInteger connectionIds = new AtomicInteger(0);
	// private static final Set<WebsocketChat> connections = new
	// CopyOnWriteArraySet<WebsocketChat>();
	// private static final Map<String, Session> connectionMap= new
	// HashMap<String,Session>();
	private static final ConcurrentHashMap<String, Session> concurrentMap = new ConcurrentHashMap<String, Session>();

	private final String nickname;
	private Session session;

	public WebsocketChat() {
		nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
	}

	/**
	 * create connect
	 * 
	 * @param session
	 */
	@OnOpen
	public void start(Session session, EndpointConfig config) {
		// public void start(Session session) {
		// System.out.println(session.getUserProperties().get("Uname"));

		System.out.println(session.getQueryString());
		System.out.println(session.getPathParameters());
		this.session = session;
		String uname = session.getUserProperties().get("Uname") + "";
		// connectionMap.put(this.nickname, this.session);
		try {
			Session sessionitem = concurrentMap.get(uname);
			if (sessionitem != null) {
				broadcastOneToOne(uname+",You are forced underlineto"+uname,uname);
				sessionitem.close();
			}
			//System.out.println(sessionitem);

		} catch (Exception e1) {
			System.out.println("exception le");
		}
		concurrentMap.put(uname, this.session);
		// }

		String message = String.format("* %s %s", nickname, "join chat room");
		broadcast(message);
		try {
			// SendHello(this.nickname);
			SendHello(uname);
			onlineList();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	@OnClose
	public void end(Session session) {
		String uname = (String) session.getUserProperties().get("Uname");
		// connections.remove(this);
		try {
			synchronized (concurrentMap) {
				concurrentMap.remove(uname);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}

		String message = String.format("* %s %s", nickname, "exit");
		broadcast(message);
	}

	@OnMessage
	public void incoming(String message, Session session) {
		String uname = (String) session.getUserProperties().get("Uname");
		//System.out.println((String) session.getUserProperties().get("YYYY"));
		// Never trust the client
		String m = String.format("* from: %s==>%s", uname, message);
		if (m.contains("to")) {
			// single send
			broadcastOneToOne(m, uname);
		} else {
			// all broadcast
			broadcast(m);
		}
	}

	@OnError
	public void onError(Throwable t) throws Throwable {
		System.out.println("errorttttttttt: " + t.toString());
	}

	private static void broadcast(String msg) {
		Set<Map.Entry<String, Session>> entryall = concurrentMap.entrySet();
		for (Map.Entry<String, Session> client : entryall) {
			try {
				synchronized (client) {
					client.getValue().getBasicRemote().sendText(msg);
				}
			} catch (IOException e) {
				System.out.println("error:send error");
				concurrentMap.remove(client.getKey());
				try {
					client.getValue().close();
				} catch (IOException e1) {
					System.out.println("error ==============");
					e1.printStackTrace();
				}
				String message = String.format("* %s %s", client.getKey(),
						"exit");
				broadcast(message);
			}
		}
	}

	static void broadcastOneToOne(String msg, String nickName) {
		String[] arr = msg.split("to");
		Set<Map.Entry<String, Session>> alluser = concurrentMap.entrySet();
		Iterator<Map.Entry<String, Session>> mapentry = concurrentMap
				.entrySet().iterator();
		while (mapentry.hasNext()) {
			Map.Entry<String, Session> item = mapentry.next();
			String uname = item.getKey();
			try {
				if (arr[1].equals(uname) || nickName.equals(uname)) {
					synchronized (item.getValue()) {
						item.getValue().getBasicRemote().sendText(arr[0]);
					}
				}
			} catch (IOException e) {
				System.out.println("error:send error");
				concurrentMap.remove(uname);
				try {
					item.getValue().close();
				} catch (IOException e1) {
					e1.printStackTrace();
					System.out.println("error-------------------");
				}
				String message = String.format("* %s %s", uname, "exit");
				broadcast(message);
			}
		}
	}

	// greetings
	private static void SendHello(String nickName) throws IOException {

		String m = String.format("* %s %s", nickName, "hello");
		Session usersesssion = concurrentMap.get(nickName);
		usersesssion.getBasicRemote().sendText(m);
	}

	private static void onlineList() throws IOException {
		String online = "";
		Set<Map.Entry<String, Session>> alluser = concurrentMap.entrySet();
		for (Map.Entry<String, Session> entry : alluser) {
			if (online.equals("")) {
				online = entry.getKey();
			} else {
				online += "," + entry.getKey();
			}

		}
		String m = String.format("* %s %s", "current online users are==>",
				online);
		for (Map.Entry<String, Session> entry : alluser) {
			entry.getValue().getBasicRemote().sendText(m);
		}

	}
}
